1 /*
2  * Unity VSCode Support
3  *
4  * Seamless support
for Microsoft Visual Studio Code in Unity
5  *
6  * Version:
7  *
2.7
8  *
9  * Authors:
10  * Matthew Davey <matthew.davey@dotbunny.com>
11  */

12 namespace
dotBunny.Unity
13 {
14     
using System;
15     
using System.IO;
16     
using System.Text.RegularExpressions;
17     
using UnityEditor;
18     
using UnityEngine;
19
20     
[InitializeOnLoad]
21     
public static class VSCode
22     {

23         ///
<summary>
24         ///
Current Version Number
25         ///
</summary>
26         
public const float Version = 2.7f;
27
28         ///
<summary>
29         ///
Current Version Code
30         ///
</summary>
31         
public const string VersionCode = "-RELEASE";
32         
33         ///
<summary>
34         ///
Additional File Extensions
35         ///
</summary>
36         
public const string FileExtensions = ".ts, .bjs, .javascript, .json, .html";
37         
38         ///
<summary>
39         ///
Download URL for Unity Debbuger
40         ///
</summary>
41         
public const string UnityDebuggerURL = "https://unity.gallery.vsassets.io/_apis/public/gallery/publisher/unity/extension/unity-debug/latest/assetbyname/Microsoft.VisualStudio.Services.VSIXPackage";
42
43         
#region Properties
44
45         ///
<summary>
46         ///
Path to VSCode executable
47         
public static string CodePath
48         {
49             
get
50             {
51                 
string current = EditorPrefs.GetString("VSCode_CodePath", "");
52                 
if(current == "" || !VSCodeExists(current))
53                 {
54                     
//Value not set, set to "" or current path is invalid, try to autodetect it
55                     
//If autodetect fails, a error will be printed and the default value set
56                     EditorPrefs.SetString(
"VSCode_CodePath", AutodetectCodePath());
57                     
//If its not installed or the install folder isn't a "normal" one,
58                     
//AutodetectCodePath will print a error message to the Unity Console
59                 }
60                 
return EditorPrefs.GetString("VSCode_CodePath", current);
61             }
62             
set
63             {
64                 EditorPrefs.SetString(
"VSCode_CodePath", value);
65             }
66         }

67         
68         ///
<summary>
69         ///
Get Program Files Path
70         ///
</summary>
71         ///
<returns>The platforms "Program Files" path.</returns>
72         
static string ProgramFilesx86()
73         {
74             
if( 8 == IntPtr.Size
75                 || (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable(
"PROCESSOR_ARCHITEW6432"))))
76             {
77                 
return Environment.GetEnvironmentVariable("ProgramFiles(x86)");
78             }
79
80             
return Environment.GetEnvironmentVariable("ProgramFiles");
81         }

82         
83         
84         ///
<summary>
85         ///
Should debug information be displayed in the Unity terminal?
86         ///
</summary>
87         
public static bool Debug
88         {
89             
get
90             {
91                 
return EditorPrefs.GetBool("VSCode_Debug", false);
92             }
93             
set
94             {
95                 EditorPrefs.SetBool(
"VSCode_Debug", value);
96             }
97         }

98
99         ///
<summary>
100         ///
Is the Visual Studio Code Integration Enabled?
101         ///
</summary>
102         ///
<remarks>
103         ///
We do not want to automatically turn it on, for in larger projects not everyone is using VSCode
104         ///
</remarks>
105         
public static bool Enabled
106         {
107             
get
108             {
109                 
return EditorPrefs.GetBool("VSCode_Enabled", false);
110             }
111             
set
112             {
113                 
// When turning the plugin on, we should remove all the previous project files
114                 
if (!Enabled && value)
115                 {
116                     ClearProjectFiles();
117                 }
118                 EditorPrefs.SetBool(
"VSCode_Enabled", value);
119             }
120         }
121         
public static bool UseUnityDebugger
122         {
123             
get
124             {
125                 
return EditorPrefs.GetBool("VSCode_UseUnityDebugger", false);
126             }
127             
set
128             {
129                 
if ( value != UseUnityDebugger ) {
130                     
131                     
// Set value
132                     EditorPrefs.SetBool(
"VSCode_UseUnityDebugger", value);
133                     
134                     
// Do not write the launch JSON file because the debugger uses its own
135                     
if ( value ) {
136                         WriteLaunchFile =
false;
137                     }
138                     
139                     
// Update launch file
140                     UpdateLaunchFile();
141                 }
142             }
143         }

144         
145         ///
<summary>
146         ///
When opening a project in Unity, should it automatically open in VS Code.
147         ///
</summary>
148         
public static bool AutoOpenEnabled
149         {
150             
get
151             {
152                 
return EditorPrefs.GetBool("VSCode_AutoOpenEnabled", false);
153             }
154             
set
155             {
156                 EditorPrefs.SetBool(
"VSCode_AutoOpenEnabled", value);
157             }
158         }

159
160         ///
<summary>
161         ///
Should the launch.json file be written?
162         ///
</summary>
163         ///
<remarks>
164         ///
Useful to disable if someone has their own custom one rigged up
165         ///
</remarks>
166         
public static bool WriteLaunchFile
167         {
168             
get
169             {
170                 
return EditorPrefs.GetBool("VSCode_WriteLaunchFile", true);
171             }
172             
set
173             {
174                 EditorPrefs.SetBool(
"VSCode_WriteLaunchFile", value);
175             }
176         }

177
178         ///
<summary>
179         ///
Should the plugin automatically update itself.
180         ///
</summary>
181         
static bool AutomaticUpdates
182         {
183             
get
184             {
185                 
return EditorPrefs.GetBool("VSCode_AutomaticUpdates", false);
186             }
187             
set
188             {
189                 EditorPrefs.SetBool(
"VSCode_AutomaticUpdates", value);
190             }
191         }
192
193         
static float GitHubVersion
194         {
195             
get
196             {
197                 
return EditorPrefs.GetFloat("VSCode_GitHubVersion", Version);
198             }
199             
set
200             {
201                 EditorPrefs.SetFloat(
"VSCode_GitHubVersion", value);
202             }
203         }

204
205         ///
<summary>
206         ///
When was the last time that the plugin was updated?
207         ///
</summary>
208         
static DateTime LastUpdate
209         {
210             
get
211             {
212                 
// Feature creation date.
213                 DateTime lastTime =
new DateTime(2015, 10, 8);
214
215                 
if (EditorPrefs.HasKey("VSCode_LastUpdate"))
216                 {
217                     DateTime.TryParse(EditorPrefs.GetString(
"VSCode_LastUpdate"), out lastTime);
218                 }
219                 
return lastTime;
220             }
221             
set
222             {
223                 EditorPrefs.SetString(
"VSCode_LastUpdate", value.ToString());
224             }
225         }

226
227         ///
<summary>
228         ///
Quick reference to the VSCode launch settings file
229         ///
</summary>
230         
static string LaunchPath
231         {
232             
get
233             {
234                 
return SettingsFolder + System.IO.Path.DirectorySeparatorChar + "launch.json";
235             }
236         }

237
238         ///
<summary>
239         ///
The full path to the project
240         ///
</summary>
241         
static string ProjectPath
242         {
243             
get
244             {
245                 
return System.IO.Path.GetDirectoryName(UnityEngine.Application.dataPath);
246             }
247         }

248
249         ///
<summary>
250         ///
Should the script editor be reverted when quiting Unity.
251         ///
</summary>
252         ///
<remarks>
253         ///
Useful for environments where you do not use VSCode for everything.
254         ///
</remarks>
255         
static bool RevertExternalScriptEditorOnExit
256         {
257             
get
258             {
259                 
return EditorPrefs.GetBool("VSCode_RevertScriptEditorOnExit", true);
260             }
261             
set
262             {
263                 EditorPrefs.SetBool(
"VSCode_RevertScriptEditorOnExit", value);
264             }
265         }

266
267         ///
<summary>
268         ///
Quick reference to the VSCode settings folder
269         ///
</summary>
270         
static string SettingsFolder
271         {
272             
get
273             {
274                 
return ProjectPath + System.IO.Path.DirectorySeparatorChar + ".vscode";
275             }
276         }
277
278         
static string SettingsPath
279         {
280
281             
get
282             {
283                 
return SettingsFolder + System.IO.Path.DirectorySeparatorChar + "settings.json";
284             }
285         }
286
287         
static int UpdateTime
288         {
289             
get
290             {
291                 
return EditorPrefs.GetInt("VSCode_UpdateTime", 7);
292             }
293             
set
294             {
295                 EditorPrefs.SetInt(
"VSCode_UpdateTime", value);
296             }
297         }
298
299         
#endregion
300
301         ///
<summary>
302         ///
Integration Constructor
303         ///
</summary>
304         
static VSCode()
305         {
306             
if (Enabled)
307             {
308                 UpdateUnityPreferences(
true);
309                 UpdateLaunchFile();
310                 
311                 
// Add Update Check
312                 DateTime targetDate = LastUpdate.AddDays(UpdateTime);
313                 
if (DateTime.Now >= targetDate && AutomaticUpdates)
314                 {
315                     CheckForUpdate();
316                 }
317
318                 
// Open VS Code automatically when project is loaded
319                 
if (AutoOpenEnabled)
320                 {
321                     CheckForAutoOpen();
322                 }
323                 
324             }
325             
326             
// Event for when script is reloaded
327             System.AppDomain.CurrentDomain.DomainUnload += System_AppDomain_CurrentDomain_DomainUnload;
328         }
329         
static void System_AppDomain_CurrentDomain_DomainUnload(object sender, System.EventArgs e)
330         {
331             
if (Enabled && RevertExternalScriptEditorOnExit)
332             {
333                 UpdateUnityPreferences(
false);
334             }
335         }
336
337
338         
#region Public Members
339
340         ///
<summary>
341         ///
Force Unity To Write Project File
342         ///
</summary>
343         ///
<remarks>
344         ///
Reflection!
345         ///
</remarks>
346         
public static void SyncSolution()
347         {
348             System.Type T = System.Type.GetType(
"UnityEditor.SyncVS,UnityEditor");
349             System.Reflection.MethodInfo SyncSolution = T.GetMethod(
"SyncSolution", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
350             SyncSolution.Invoke(
null, null);
351
352         }

353
354         ///
<summary>
355         ///
Update the solution files so that they work with VS Code
356         ///
</summary>
357         
public static void UpdateSolution()
358         {
359             
// No need to process if we are not enabled
360             
if (!VSCode.Enabled)
361             {
362                 
return;
363             }
364
365             
if (VSCode.Debug)
366             {
367                 UnityEngine.Debug.Log(
"[VSCode] Updating Solution & Project Files");
368             }
369
370             
var currentDirectory = Directory.GetCurrentDirectory();
371             
var solutionFiles = Directory.GetFiles(currentDirectory, "*.sln");
372             
var projectFiles = Directory.GetFiles(currentDirectory, "*.csproj");
373
374             
foreach (var filePath in solutionFiles)
375             {
376                 
string content = File.ReadAllText(filePath);
377                 content = ScrubSolutionContent(content);
378
379                 File.WriteAllText(filePath, content);
380
381                 ScrubFile(filePath);
382             }
383
384             
foreach (var filePath in projectFiles)
385             {
386                 
string content = File.ReadAllText(filePath);
387                 content = ScrubProjectContent(content);
388
389                 File.WriteAllText(filePath, content);
390
391                 ScrubFile(filePath);
392             }
393
394         }
395
396         
#endregion
397
398         
#region Private Members
399     
400         ///
<summary>
401         ///
Try to find automatically the installation of VSCode
402         ///
</summary>
403         
static string AutodetectCodePath()
404         {
405             
string[] possiblePaths =
406 #
if UNITY_EDITOR_OSX
407             {
408                 
"/Applications/Visual Studio Code.app",
409                 
"/Applications/Visual Studio Code - Insiders.app"
410             };
411 #elif UNITY_EDITOR_WIN
412             {
413                 ProgramFilesx86() + Path.DirectorySeparatorChar +
"Microsoft VS Code"
414                 + Path.DirectorySeparatorChar +
"bin" + Path.DirectorySeparatorChar + "code.cmd",
415                 ProgramFilesx86() + Path.DirectorySeparatorChar +
"Microsoft VS Code Insiders"
416                 + Path.DirectorySeparatorChar +
"bin" + Path.DirectorySeparatorChar + "code-insiders.cmd"
417             };
418 #
else
419             {
420                 
"/usr/bin/code",
421                 
"/bin/code",
422                 
"/usr/local/bin/code"
423             };
424 #endif
425             
for(int i = 0; i < possiblePaths.Length; i++)
426             {
427                 
if(VSCodeExists(possiblePaths[i]))
428                 {
429                     
return possiblePaths[i];
430                 }
431             }
432             PrintNotFound(possiblePaths[
0]);
433             
return possiblePaths[0]; //returns the default one, printing a warning message 'executable not found'
434         }

435
436         ///
<summary>
437         ///
Call VSCode with arguments
438         ///
</summary>
439         
static void CallVSCode(string args)
440         {
441             System.Diagnostics.Process proc =
new System.Diagnostics.Process();
442             
if(!VSCodeExists(CodePath))
443             {
444                 PrintNotFound(CodePath);
445                 
return;
446             }
447
448 #
if UNITY_EDITOR_OSX
449             proc.StartInfo.FileName =
"open";
450
451             
// Check the path to see if there is "Insiders"
452             
if (CodePath.Contains("Insiders"))
453             {
454                 proc.StartInfo.Arguments =
" -n -b \"com.microsoft.VSCodeInsiders\" --args " + args.Replace(@"\", @"\\");
455             }
456             
else
457             {
458                 proc.StartInfo.Arguments =
" -n -b \"com.microsoft.VSCode\" --args " + args.Replace(@"\", @"\\");
459             }
460
461             proc.StartInfo.UseShellExecute =
false;
462 #elif UNITY_EDITOR_WIN
463             proc.StartInfo.FileName = CodePath;
464             proc.StartInfo.Arguments = args;
465             proc.StartInfo.UseShellExecute =
false;
466 #
else
467             proc.StartInfo.FileName = CodePath;
468             proc.StartInfo.Arguments = args.Replace(
@"\", @"\\");
469             proc.StartInfo.UseShellExecute =
false;
470 #endif
471             proc.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
472             proc.StartInfo.CreateNoWindow =
true;
473             proc.StartInfo.RedirectStandardOutput =
true;
474             proc.Start();
475         }

476
477         ///
<summary>
478         ///
Check for Updates with GitHub
479         ///
</summary>
480         
static void CheckForUpdate()
481         {
482             
var fileContent = string.Empty;
483
484             EditorUtility.DisplayProgressBar(
"VSCode", "Checking for updates ...", 0.5f);
485
486             
// Because were not a runtime framework, lets just use the simplest way of doing this
487             
try
488             {
489                 
using (var webClient = new System.Net.WebClient())
490                 {
491                     fileContent = webClient.DownloadString(
"https://raw.githubusercontent.com/dotBunny/VSCode/master/Plugins/Editor/VSCode.cs");
492                 }
493             }
494             
catch (Exception e)
495             {
496                 
if (Debug)
497                 {
498                     UnityEngine.Debug.Log(
"[VSCode] " + e.Message);
499
500                 }
501
502                 
// Don't go any further if there is an error
503                 
return;
504             }
505             
finally
506             {
507                 EditorUtility.ClearProgressBar();
508             }
509
510             
// Set the last update time
511             LastUpdate = DateTime.Now;
512
513             
// Fix for oddity in downlo
514             
if (fileContent.Substring(0, 2) != "/*")
515             {
516                 
int startPosition = fileContent.IndexOf("/*", StringComparison.CurrentCultureIgnoreCase);
517
518                 // Jump over junk characters
519                 fileContent = fileContent.Substring(startPosition);
520             }
521
522             
string[] fileExploded = fileContent.Split('\n');
523             
if (fileExploded.Length > 7)
524             {
525                 
float github = Version;
526                 
if (float.TryParse(fileExploded[6].Replace("*", "").Trim(), out github))
527                 {
528                     GitHubVersion = github;
529                 }
530
531
532                 
if (github > Version)
533                 {
534                     
var GUIDs = AssetDatabase.FindAssets("t:Script VSCode");
535                     
var path = Application.dataPath.Substring(0, Application.dataPath.Length - "/Assets".Length) + System.IO.Path.DirectorySeparatorChar +
536                                AssetDatabase.GUIDToAssetPath(GUIDs[
0]).Replace('/', System.IO.Path.DirectorySeparatorChar);
537
538                     
if (EditorUtility.DisplayDialog("VSCode Update", "A newer version of the VSCode plugin is available, would you like to update your version?", "Yes", "No"))
539                     {
540                         // Always make sure the file
is writable
541                         System.IO.FileInfo fileInfo =
new System.IO.FileInfo(path);
542                         fileInfo.IsReadOnly =
false;
543
544                         // Write update file
545                         File.WriteAllText(path, fileContent);
546
547                         // Force update
on text file
548                         AssetDatabase.ImportAsset(AssetDatabase.GUIDToAssetPath(GUIDs[
0]), ImportAssetOptions.ForceUpdate);
549                     }
550
551                 }
552             }
553         }

554
555         ///
<summary>
556         ///
Checks whether it should auto-open VSCode
557         ///
</summary>
558         ///
<remarks>
559         ///
VSCode() gets called on Launch and Run, through IntializeOnLoad
560         ///
https://docs.unity3d.com/ScriptReference/InitializeOnLoadAttribute.html
561         ///
To make sure it only opens VSCode when Unity (re)launches (i.e. opens a project),
562         ///
we compare the launch time, which we calculate using EditorApplication.timeSinceStartup.
563         ///
</remarks>
564         
static void CheckForAutoOpen()
565         {
566             
double timeInSeconds = (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds;
567             
int unityLaunchTimeInSeconds = (int)(timeInSeconds - EditorApplication.timeSinceStartup);
568             
int prevUnityLaunchTime = EditorPrefs.GetInt("VSCode_UnityLaunchTime", 0);
569             // If launch time has changed, then Unity was re-opened
570             
if (unityLaunchTimeInSeconds > prevUnityLaunchTime) {
571                 // Launch VSCode
572                 VSCode.MenuOpenProject();
573                 // Save
new launch time
574                 EditorPrefs.SetInt(
"VSCode_UnityLaunchTime", unityLaunchTimeInSeconds);
575             }
576         }

577
578         ///
<summary>
579         ///
Clear out any existing project files and lingering stuff that might cause problems
580         ///
</summary>
581         
static void ClearProjectFiles()
582         {
583             
var currentDirectory = Directory.GetCurrentDirectory();
584             
var solutionFiles = Directory.GetFiles(currentDirectory, "*.sln");
585             
var projectFiles = Directory.GetFiles(currentDirectory, "*.csproj");
586             
var unityProjectFiles = Directory.GetFiles(currentDirectory, "*.unityproj");
587
588             
foreach (string solutionFile in solutionFiles)
589             {
590                 File.Delete(solutionFile);
591             }
592             
foreach (string projectFile in projectFiles)
593             {
594                 File.Delete(projectFile);
595             }
596             
foreach (string unityProjectFile in unityProjectFiles)
597             {
598                 File.Delete(unityProjectFile);
599             }
600
601             // Replace with our clean files (only
in Unity 5)
602 #
if !UNITY_4_0 && !UNITY_4_1 && !UNITY_4_2 && !UNITY_4_3 && !UNITY_4_5 && !UNITY_4_6 && !UNITY_4_7
603             SyncSolution();
604 #endif
605         }

606
607         ///
<summary>
608         ///
Force Unity Preferences Window To Read From Settings
609         ///
</summary>
610         
static void FixUnityPreferences()
611         {
612             // I want that window, please and thank you
613             System.Type T = System.Type.GetType(
"UnityEditor.PreferencesWindow,UnityEditor");
614
615             
if (EditorWindow.focusedWindow == null)
616                 
return;
617
618             // Only run
this when the editor window is visible (cause its what screwed us up)
619             
if (EditorWindow.focusedWindow.GetType() == T)
620             {
621                 
var window = EditorWindow.GetWindow(T, true, "Unity Preferences");
622
623
624                 
if (window == null)
625                 {
626                     
if (Debug)
627                     {
628                         UnityEngine.Debug.Log(
"[VSCode] No Preferences Window Found (really?)");
629                     }
630                     
return;
631                 }
632
633                 
var invokerType = window.GetType();
634                 
var invokerMethod = invokerType.GetMethod("ReadPreferences",
635                     System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
636
637                 
if (invokerMethod != null)
638                 {
639                     invokerMethod.Invoke(window,
null);
640                 }
641                 
else if (Debug)
642                 {
643                     UnityEngine.Debug.Log(
"[VSCode] No Reflection Method Found For Preferences");
644                 }
645             }
646         }

647
648         ///
<summary>
649         ///
Determine what port Unity is listening for on Windows
650         ///
</summary>
651         
static int GetDebugPort()
652         {
653 #
if UNITY_EDITOR_WIN
654             System.Diagnostics.Process process =
new System.Diagnostics.Process();
655             process.StartInfo.FileName =
"netstat";
656             process.StartInfo.Arguments =
"-a -n -o -p TCP";
657             process.StartInfo.UseShellExecute =
false;
658             process.StartInfo.RedirectStandardOutput =
true;
659             process.Start();
660
661             
string output = process.StandardOutput.ReadToEnd();
662             
string[] lines = output.Split('\n');
663
664             process.WaitForExit();
665
666             
foreach (string line in lines)
667             {
668                 
string[] tokens = Regex.Split(line, "\\s+");
669                 
if (tokens.Length > 4)
670                 {
671                     
int test = -1;
672                     
int.TryParse(tokens[5], out test);
673
674                     
if (test > 1023)
675                     {
676                         
try
677                         {
678                             
var p = System.Diagnostics.Process.GetProcessById(test);
679                             
if (p.ProcessName == "Unity")
680                             {
681                                 
return test;
682                             }
683                         }
684                         
catch
685                         {
686
687                         }
688                     }
689                 }
690             }
691 #
else
692             System.Diagnostics.Process process =
new System.Diagnostics.Process();
693             process.StartInfo.FileName =
"lsof";
694             process.StartInfo.Arguments =
"-c /^Unity$/ -i 4tcp -a";
695             process.StartInfo.UseShellExecute =
false;
696             process.StartInfo.RedirectStandardOutput =
true;
697             process.Start();
698
699             // Not thread safe (yet!)
700             
string output = process.StandardOutput.ReadToEnd();
701             
string[] lines = output.Split('\n');
702
703             process.WaitForExit();
704
705             
foreach (string line in lines)
706             {
707                 
int port = -1;
708                 
if (line.StartsWith("Unity"))
709                 {
710                     
string[] portions = line.Split(new string[] { "TCP *:" }, System.StringSplitOptions.None);
711                     
if (portions.Length >= 2)
712                     {
713                         Regex digitsOnly =
new Regex(@"[^\d]");
714                         
string cleanPort = digitsOnly.Replace(portions[1], "");
715                         
if (int.TryParse(cleanPort, out port))
716                         {
717                             
if (port > -1)
718                             {
719                                 
return port;
720                             }
721                         }
722                     }
723                 }
724             }
725 #endif
726             
return -1;
727         }

728
729         ///
<summary>
730         ///
Manually install the original Unity Debuger
731         ///
</summary>
732         ///
<remarks>
733         ///
This should auto update to the latest.
734         ///
</remarks>
735         
static void InstallUnityDebugger()
736         {
737             EditorUtility.DisplayProgressBar(
"VSCode", "Downloading Unity Debugger ...", 0.1f);
738             
byte[] fileContent;
739             
740             
try
741             {
742                 
using (var webClient = new System.Net.WebClient())
743                 {
744                     fileContent = webClient.DownloadData(UnityDebuggerURL);
745                 }
746             }
747             
catch (Exception e)
748             {
749                 
if (Debug)
750                 {
751                     UnityEngine.Debug.Log(
"[VSCode] " + e.Message);
752                 }
753                 // Don
't go any further if there is an error
754                 
return;
755             }
756             
finally
757             {
758                 EditorUtility.ClearProgressBar();
759             }
760             
761             // Do we have a file to install?
762             
if ( fileContent != null ) {
763                 
string fileName = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".vsix";
764                 File.WriteAllBytes(fileName, fileContent);
765                 
766                 CallVSCode(fileName);
767             }
768
769         }
770    
771         // HACK: This
is in until Unity can figure out why MD keeps opening even though a different program is selected.
772         [MenuItem(
"Assets/Open C# Project In Code", false, 1000)]
773         
static void MenuOpenProject()
774         {
775             // Force the project files to be sync
776             SyncSolution();
777
778             // Load Project
779             CallVSCode(
"\"" + ProjectPath + "\"");
780         }

781
782         ///
<summary>
783         ///
Print a error message to the Unity Console about not finding the code executable
784         ///
</summary>
785         
static void PrintNotFound(string path)
786         {
787             UnityEngine.Debug.LogError(
"[VSCode] Code executable in '" + path + "' not found. Check your" +
788             
"Visual Studio Code installation and insert the correct path in the Preferences menu.");
789         }
790
791         [MenuItem(
"Assets/Open C# Project In Code", true, 1000)]
792         
static bool ValidateMenuOpenProject()
793         {
794             
return Enabled;
795         }

796
797         ///
<summary>
798         ///
VS Code Integration Preferences Item
799         ///
</summary>
800         ///
<remarks>
801         ///
Contains all 3 toggles: Enable/Disable; Debug On/Off; Writing Launch File On/Off
802         ///
</remarks>
803         [PreferenceItem(
"VSCode")]
804         
static void VSCodePreferencesItem()
805         {
806             
if (EditorApplication.isCompiling)
807             {
808                 EditorGUILayout.HelpBox(
"Please wait for Unity to finish compiling. \nIf the window doesn't refresh, simply click on the window or move it around to cause a repaint to happen.", MessageType.Warning);
809                 
return;
810             }
811             EditorGUILayout.BeginVertical();
812
813             
var developmentInfo = "Support development of this plugin, follow @reapazor and @dotbunny on Twitter.";
814             
var versionInfo = string.Format("{0:0.00}", Version) + VersionCode + ", GitHub version @ " + string.Format("{0:0.00}", GitHubVersion);
815             EditorGUILayout.HelpBox(developmentInfo +
" --- [ " + versionInfo + " ]", MessageType.None);
816
817             EditorGUI.BeginChangeCheck();
818             
819 // Need the VS Code executable
820             EditorGUILayout.BeginHorizontal();
821             EditorGUILayout.LabelField(
"VS Code Path", GUILayout.Width(75));
822 #
if UNITY_5_3_OR_NEWER
823             CodePath = EditorGUILayout.DelayedTextField(CodePath, GUILayout.ExpandWidth(
true));
824 #
else
825             CodePath = EditorGUILayout.TextField(CodePath, GUILayout.ExpandWidth(
true));
826 #endif
827             GUI.SetNextControlName(
"PathSetButton");
828             
if(GUILayout.Button("...", GUILayout.Height(14), GUILayout.Width(20)))
829             {
830                 GUI.FocusControl(
"PathSetButton");
831                 
string path = EditorUtility.OpenFilePanel( "Visual Studio Code Executable", "", "" );
832                 
if( path.Length != 0 && File.Exists(path) || Directory.Exists(path))
833                 {
834                     CodePath = path;
835                 }
836             }
837             EditorGUILayout.EndHorizontal();
838             EditorGUILayout.Space();
839
840             Enabled = EditorGUILayout.Toggle(
new GUIContent("Enable Integration", "Should the integration work its magic for you?"), Enabled);
841
842             UseUnityDebugger = EditorGUILayout.Toggle(
new GUIContent("Use Unity Debugger", "Should the integration integrate with Unity's VSCode Extension (must be installed)."), UseUnityDebugger);
843
844             AutoOpenEnabled = EditorGUILayout.Toggle(
new GUIContent("Enable Auto Open", "When opening a project in Unity, should it automatically open in VS Code?"), AutoOpenEnabled);
845
846             EditorGUILayout.Space();
847             RevertExternalScriptEditorOnExit = EditorGUILayout.Toggle(
new GUIContent("Revert Script Editor On Unload", "Should the external script editor setting be reverted to its previous setting on project unload? This is useful if you do not use Code with all your projects."),RevertExternalScriptEditorOnExit);
848             
849             Debug = EditorGUILayout.Toggle(
new GUIContent("Output Messages To Console", "Should informational messages be sent to Unity's Console?"), Debug);
850
851             WriteLaunchFile = EditorGUILayout.Toggle(
new GUIContent("Always Write Launch File", "Always write the launch.json settings when entering play mode?"), WriteLaunchFile);
852
853             EditorGUILayout.Space();
854
855             AutomaticUpdates = EditorGUILayout.Toggle(
new GUIContent("Automatic Updates", "Should the plugin automatically update itself?"), AutomaticUpdates);
856
857             UpdateTime = EditorGUILayout.IntSlider(
new GUIContent("Update Timer (Days)", "After how many days should updates be checked for?"), UpdateTime, 1, 31);
858
859             EditorGUILayout.Space();
860             EditorGUILayout.Space();
861
862             
if (EditorGUI.EndChangeCheck())
863             {
864                 UpdateUnityPreferences(Enabled);
865
866                 // TODO: Force Unity To Reload Preferences
867                 // This seems to be a hick up / issue
868                 
if (VSCode.Debug)
869                 {
870                     
if (Enabled)
871                     {
872                         UnityEngine.Debug.Log(
"[VSCode] Integration Enabled");
873                     }
874                     
else
875                     {
876                         UnityEngine.Debug.Log(
"[VSCode] Integration Disabled");
877                     }
878                 }
879             }
880
881             
if (GUILayout.Button(new GUIContent("Force Update", "Check for updates to the plugin, right NOW!")))
882             {
883                 CheckForUpdate();
884                 EditorGUILayout.EndVertical();
885                 
return;
886             }
887             
if (GUILayout.Button(new GUIContent("Write Workspace Settings", "Output a default set of workspace settings for VSCode to use, ignoring many different types of files.")))
888             {
889                 WriteWorkspaceSettings();
890                 EditorGUILayout.EndVertical();
891                 
return;
892             }
893             EditorGUILayout.Space();
894
895             
if (UseUnityDebugger)
896             {
897                 EditorGUILayout.HelpBox(
"In order for the \"Use Unity Debuggger\" option to function above, you need to have installed the Unity Debugger Extension for Visual Studio Code.", MessageType.Warning);
898                 
if (GUILayout.Button(new GUIContent("Install Unity Debugger", "Install the Unity Debugger Extension into Code")))
899                 {
900                     InstallUnityDebugger();
901                     EditorGUILayout.EndVertical();
902                     
return;
903                 }
904             }
905
906         }

907
908         ///
<summary>
909         ///
Asset Open Callback (from Unity)
910         ///
</summary>
911         ///
<remarks>
912         ///
Called when Unity is about to open an asset.
913         ///
</remarks>
914         [UnityEditor.Callbacks.OnOpenAssetAttribute()]
915         
static bool OnOpenedAsset(int instanceID, int line)
916         {
917             // bail
out if we are not using VSCode
918             
if (!Enabled)
919             {
920                 
return false;
921             }
922
923             // current path without the asset folder
924             
string appPath = ProjectPath;
925
926             // determine asset that has been
double clicked in the project view
927             UnityEngine.Object selected = EditorUtility.InstanceIDToObject(instanceID);
928
929             // additional file extensions
930             
string selectedFilePath = AssetDatabase.GetAssetPath(selected);
931             
string selectedFileExt = Path.GetExtension(selectedFilePath);
932             
if (selectedFileExt == null) {
933                 selectedFileExt = String.Empty;
934             }
935             
if (!String.IsNullOrEmpty(selectedFileExt)) {
936                 selectedFileExt = selectedFileExt.ToLower();
937             }
938
939             // open supported
object types
940             
if (selected.GetType().ToString() == "UnityEditor.MonoScript" ||
941                 selected.GetType().ToString() ==
"UnityEngine.Shader" ||
942                 VSCode.FileExtensions.IndexOf(selectedFileExt, StringComparison.OrdinalIgnoreCase) >=
0)
943             {
944                 
string completeFilepath = appPath + Path.DirectorySeparatorChar + AssetDatabase.GetAssetPath(selected);
945
946                 
string args = null;
947                 
if (line == -1)
948                 {
949                     args =
"\"" + ProjectPath + "\" \"" + completeFilepath + "\" -r";
950                 }
951                 
else
952                 {
953                     args =
"\"" + ProjectPath + "\" -g \"" + completeFilepath + ":" + line.ToString() + "\" -r";
954                 }
955                 // call
'open'
956                 CallVSCode(args);
957
958                 
return true;
959             }
960
961             // Didnt find a code file?
let Unity figure it out
962             
return false;
963
964         }

965
966         ///
<summary>
967         ///
Executed when the Editor's playmode changes allowing for capture of required data
968         ///
</summary>
969         
static void OnPlaymodeStateChanged()
970         {
971             
if (UnityEngine.Application.isPlaying && EditorApplication.isPlayingOrWillChangePlaymode)
972             {
973                 UpdateLaunchFile();
974             }
975         }

976
977         ///
<summary>
978         ///
Detect when scripts are reloaded and relink playmode detection
979         ///
</summary>
980         [UnityEditor.Callbacks.DidReloadScripts()]
981         
static void OnScriptReload()
982         {
983             EditorApplication.playmodeStateChanged -= OnPlaymodeStateChanged;
984             EditorApplication.playmodeStateChanged += OnPlaymodeStateChanged;
985         }

986
987         ///
<summary>
988         ///
Remove extra/erroneous lines from a file.
989         
static void ScrubFile(string path)
990         {
991             
string[] lines = File.ReadAllLines(path);
992             System.Collections.Generic.List<
string> newLines = new System.Collections.Generic.List<string>();
993             
for (int i = 0; i < lines.Length; i++)
994             {
995                 // Check Empty
996                 
if (string.IsNullOrEmpty(lines[i].Trim()) || lines[i].Trim() == "\t" || lines[i].Trim() == "\t\t")
997                 {
998
999                 }
1000                 
else
1001                 {
1002                     newLines.Add(lines[i]);
1003                 }
1004             }
1005             File.WriteAllLines(path, newLines.ToArray());
1006         }

1007
1008         ///
<summary>
1009         ///
Remove extra/erroneous data from project file (content).
1010         ///
</summary>
1011         
static string ScrubProjectContent(string content)
1012         {
1013             
if (content.Length == 0)
1014                 
return "";
1015
1016 #
if !UNITY_EDITOR_WIN
1017             // Moved to
3.5, 2.0 is legacy.
1018             
if (content.IndexOf("<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>") != -1)
1019             {
1020                 content = Regex.Replace(content,
"<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>", "<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>");
1021             }
1022 #endif
1023
1024             
string targetPath = "";// "<TargetPath>Temp" + Path.DirectorySeparatorChar + "bin" + Path.DirectorySeparatorChar + "Debug" + Path.DirectorySeparatorChar + "</TargetPath>"; //OutputPath
1025             
string langVersion = "<LangVersion>default</LangVersion>";
1026
1027
1028             
bool found = true;
1029             
int location = 0;
1030             
string addedOptions = "";
1031             
int startLocation = -1;
1032             
int endLocation = -1;
1033             
int endLength = 0;
1034
1035             
while (found)
1036             {
1037                 startLocation = -
1;
1038                 endLocation = -
1;
1039                 endLength =
0;
1040                 addedOptions =
"";
1041                 startLocation = content.IndexOf(
"<PropertyGroup", location);
1042
1043                 
if (startLocation != -1)
1044                 {
1045
1046                     endLocation = content.IndexOf(
"</PropertyGroup>", startLocation);
1047                     endLength = (endLocation - startLocation);
1048
1049
1050                     
if (endLocation == -1)
1051                     {
1052                         found =
false;
1053                         
continue;
1054                     }
1055                     
else
1056                     {
1057                         found =
true;
1058                         location = endLocation;
1059                     }
1060
1061                     
if (content.Substring(startLocation, endLength).IndexOf("<TargetPath>") == -1)
1062                     {
1063                         addedOptions +=
"\n\r\t" + targetPath + "\n\r";
1064                     }
1065
1066                     
if (content.Substring(startLocation, endLength).IndexOf("<LangVersion>") == -1)
1067                     {
1068                         addedOptions +=
"\n\r\t" + langVersion + "\n\r";
1069                     }
1070
1071                     
if (!string.IsNullOrEmpty(addedOptions))
1072                     {
1073                         content = content.Substring(
0, endLocation) + addedOptions + content.Substring(endLocation);
1074                     }
1075                 }
1076                 
else
1077                 {
1078                     found =
false;
1079                 }
1080             }
1081
1082             
return content;
1083         }

1084
1085         ///
<summary>
1086         ///
Remove extra/erroneous data from solution file (content).
1087         ///
</summary>
1088         
static string ScrubSolutionContent(string content)
1089         {
1090             // Replace Solution Version
1091             content = content.Replace(
1092                 
"Microsoft Visual Studio Solution File, Format Version 11.00\r\n# Visual Studio 2008\r\n",
1093                 
"\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio 2012");
1094
1095             // Remove Solution Properties (Unity Junk)
1096             
int startIndex = content.IndexOf("GlobalSection(SolutionProperties) = preSolution");
1097             
if (startIndex != -1)
1098             {
1099                 
int endIndex = content.IndexOf("EndGlobalSection", startIndex);
1100                 content = content.Substring(
0, startIndex) + content.Substring(endIndex + 16);
1101             }
1102
1103             
return content;
1104         }

1105        
1106         ///
<summary>
1107         ///
Update Visual Studio Code Launch file
1108         ///
</summary>
1109         
static void UpdateLaunchFile()
1110         {
1111             
if (!VSCode.Enabled)
1112             {
1113                 
return;
1114             }
1115             
else if (VSCode.UseUnityDebugger)
1116             {
1117                 
if (!Directory.Exists(VSCode.SettingsFolder))
1118                     System.IO.Directory.CreateDirectory(VSCode.SettingsFolder);
1119
1120                 // Write
out proper formatted JSON (hence no more SimpleJSON here)
1121                 
string fileContent = "{\n\t\"version\": \"0.2.0\",\n\t\"configurations\": [\n\t\t{\n\t\t\t\"name\": \"Unity Editor\",\n\t\t\t\"type\": \"unity\",\n\t\t\t\"request\": \"launch\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"Windows Player\",\n\t\t\t\"type\": \"unity\",\n\t\t\t\"request\": \"launch\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"OSX Player\",\n\t\t\t\"type\": \"unity\",\n\t\t\t\"request\": \"launch\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"Linux Player\",\n\t\t\t\"type\": \"unity\",\n\t\t\t\"request\": \"launch\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"iOS Player\",\n\t\t\t\"type\": \"unity\",\n\t\t\t\"request\": \"launch\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"Android Player\",\n\t\t\t\"type\": \"unity\",\n\t\t\t\"request\": \"launch\"\n\n\t\t}\n\t]\n}";
1122                 File.WriteAllText(VSCode.LaunchPath, fileContent);
1123             }
1124             
else if (VSCode.WriteLaunchFile)
1125             {
1126                 
int port = GetDebugPort();
1127                 
if (port > -1)
1128                 {
1129                     
if (!Directory.Exists(VSCode.SettingsFolder))
1130                         System.IO.Directory.CreateDirectory(VSCode.SettingsFolder);
1131
1132                     // Write
out proper formatted JSON (hence no more SimpleJSON here)
1133                     
string fileContent = "{\n\t\"version\":\"0.2.0\",\n\t\"configurations\":[ \n\t\t{\n\t\t\t\"name\":\"Unity\",\n\t\t\t\"type\":\"mono\",\n\t\t\t\"request\":\"attach\",\n\t\t\t\"address\":\"localhost\",\n\t\t\t\"port\":" + port + "\n\t\t}\n\t]\n}";
1134                     File.WriteAllText(VSCode.LaunchPath, fileContent);
1135
1136                     
if (VSCode.Debug)
1137                     {
1138                         UnityEngine.Debug.Log(
"[VSCode] Debug Port Found (" + port + ")");
1139                     }
1140                 }
1141                 
else
1142                 {
1143                     
if (VSCode.Debug)
1144                     {
1145                         UnityEngine.Debug.LogWarning(
"[VSCode] Unable to determine debug port.");
1146                     }
1147                 }
1148             }
1149         }

1150
1151         ///
<summary>
1152         ///
Update Unity Editor Preferences
1153         ///
</summary>
1154         ///
<param name="enabled">Should we turn on this party!</param>
1155         
static void UpdateUnityPreferences(bool enabled)
1156         {
1157             
if (enabled)
1158             {
1159                 // App
1160                 
if (EditorPrefs.GetString("kScriptsDefaultApp") != CodePath)
1161                 {
1162                     EditorPrefs.SetString(
"VSCode_PreviousApp", EditorPrefs.GetString("kScriptsDefaultApp"));
1163                 }
1164                 EditorPrefs.SetString(
"kScriptsDefaultApp", CodePath);
1165
1166                 // Arguments
1167                 
if (EditorPrefs.GetString("kScriptEditorArgs") != "-r -g `$(File):$(Line)`")
1168                 {
1169                     EditorPrefs.SetString(
"VSCode_PreviousArgs", EditorPrefs.GetString("kScriptEditorArgs"));
1170                 }
1171
1172                 EditorPrefs.SetString(
"kScriptEditorArgs", "-r -g `$(File):$(Line)`");
1173                 EditorPrefs.SetString(
"kScriptEditorArgs" + CodePath, "-r -g `$(File):$(Line)`");
1174
1175
1176                 // MonoDevelop Solution
1177                 
if (EditorPrefs.GetBool("kMonoDevelopSolutionProperties", false))
1178                 {
1179                     EditorPrefs.SetBool(
"VSCode_PreviousMD", true);
1180                 }
1181                 EditorPrefs.SetBool(
"kMonoDevelopSolutionProperties", false);
1182
1183                 // Support Unity Proj (JS)
1184                 
if (EditorPrefs.GetBool("kExternalEditorSupportsUnityProj", false))
1185                 {
1186                     EditorPrefs.SetBool(
"VSCode_PreviousUnityProj", true);
1187                 }
1188                 EditorPrefs.SetBool(
"kExternalEditorSupportsUnityProj", false);
1189
1190                 
if (!EditorPrefs.GetBool("AllowAttachedDebuggingOfEditor", false))
1191                 {
1192                     EditorPrefs.SetBool(
"VSCode_PreviousAttach", false);
1193                 }
1194                 EditorPrefs.SetBool(
"AllowAttachedDebuggingOfEditor", true);
1195                 
1196             }
1197             
else
1198             {
1199                 // Restore previous app
1200                 
if (!string.IsNullOrEmpty(EditorPrefs.GetString("VSCode_PreviousApp")))
1201                 {
1202                     EditorPrefs.SetString(
"kScriptsDefaultApp", EditorPrefs.GetString("VSCode_PreviousApp"));
1203                 }
1204
1205                 // Restore previous args
1206                 
if (!string.IsNullOrEmpty(EditorPrefs.GetString("VSCode_PreviousArgs")))
1207                 {
1208                     EditorPrefs.SetString(
"kScriptEditorArgs", EditorPrefs.GetString("VSCode_PreviousArgs"));
1209                 }
1210
1211                 // Restore MD setting
1212                 
if (EditorPrefs.GetBool("VSCode_PreviousMD", false))
1213                 {
1214                     EditorPrefs.SetBool(
"kMonoDevelopSolutionProperties", true);
1215                 }
1216
1217                 // Restore MD setting
1218                 
if (EditorPrefs.GetBool("VSCode_PreviousUnityProj", false))
1219                 {
1220                     EditorPrefs.SetBool(
"kExternalEditorSupportsUnityProj", true);
1221                 }
1222
1223                 // Always leave editor attaching
on, I know, it solves the problem of needing to restart for this
1224                 // to actually work
1225                 EditorPrefs.SetBool(
"AllowAttachedDebuggingOfEditor", true);
1226                 
1227             }
1228
1229             FixUnityPreferences();
1230         }

1231
1232         ///
<summary>
1233         ///
Determines if the current path to the code executable is valid or not (exists)
1234         ///
</summary>
1235         
static bool VSCodeExists(string curPath)
1236         {
1237             #
if UNITY_EDITOR_OSX
1238             
return System.IO.Directory.Exists(curPath);
1239             #
else
1240             System.IO.FileInfo code =
new System.IO.FileInfo(curPath);
1241             
return code.Exists;
1242             #endif
1243         }

1244
1245         ///
<summary>
1246         ///
Write Default Workspace Settings
1247         ///
</summary>
1248         
static void WriteWorkspaceSettings()
1249         {
1250             
if (Debug)
1251             {
1252                 UnityEngine.Debug.Log(
"[VSCode] Workspace Settings Written");
1253             }
1254
1255             
if (!Directory.Exists(VSCode.SettingsFolder))
1256             {
1257                 System.IO.Directory.CreateDirectory(VSCode.SettingsFolder);
1258             }
1259
1260             
string exclusions =
1261                 // Associations
1262                 
"{\n" +
1263                 
"\t\"files.associations\":\n" +
1264                 
"\t{\n" +
1265                 
"\t\t\"*.bjs\":\"javascript\",\n" +
1266                 
"\t\t\"*.javascript\":\"javascript\"\n" +
1267                 
"\t},\n" +
1268                 
"\t\"files.exclude\":\n" +
1269                 
"\t{\n" +
1270                 // Hidden Files
1271                 
"\t\t\"**/.DS_Store\":true,\n" +
1272                 
"\t\t\"**/.git\":true,\n" +
1273                 
"\t\t\"**/.gitignore\":true,\n" +
1274                 
"\t\t\"**/.gitattributes\":true,\n" +
1275                 
"\t\t\"**/.gitmodules\":true,\n" +
1276                 
"\t\t\"**/.svn\":true,\n" +
1277
1278
1279                 // Project Files
1280                 
"\t\t\"**/*.booproj\":true,\n" +
1281                 
"\t\t\"**/*.pidb\":true,\n" +
1282                 
"\t\t\"**/*.suo\":true,\n" +
1283                 
"\t\t\"**/*.user\":true,\n" +
1284                 
"\t\t\"**/*.userprefs\":true,\n" +
1285                 
"\t\t\"**/*.unityproj\":true,\n" +
1286                 
"\t\t\"**/*.dll\":true,\n" +
1287                 
"\t\t\"**/*.exe\":true,\n" +
1288
1289                 // Media Files
1290                 
"\t\t\"**/*.pdf\":true,\n" +
1291
1292                 // Video
1293                 
"\t\t\"**/*.mp4\":true,\n" +
1294
1295                 // Audio
1296                 
"\t\t\"**/*.mid\":true,\n" +
1297                 
"\t\t\"**/*.midi\":true,\n" +
1298                 
"\t\t\"**/*.wav\":true,\n" +
1299                 
"\t\t\"**/*.mp3\":true,\n" +
1300                 
"\t\t\"**/*.ogg\":true,\n" +
1301
1302                 // Textures
1303                 
"\t\t\"**/*.gif\":true,\n" +
1304                 
"\t\t\"**/*.ico\":true,\n" +
1305                 
"\t\t\"**/*.jpg\":true,\n" +
1306                 
"\t\t\"**/*.jpeg\":true,\n" +
1307                 
"\t\t\"**/*.png\":true,\n" +
1308                 
"\t\t\"**/*.psd\":true,\n" +
1309                 
"\t\t\"**/*.tga\":true,\n" +
1310                 
"\t\t\"**/*.tif\":true,\n" +
1311                 
"\t\t\"**/*.tiff\":true,\n" +
1312                 
"\t\t\"**/*.hdr\":true,\n" +
1313                 
"\t\t\"**/*.exr\":true,\n" +
1314
1315                 // Models
1316                 
"\t\t\"**/*.3ds\":true,\n" +
1317                 
"\t\t\"**/*.3DS\":true,\n" +
1318                 
"\t\t\"**/*.fbx\":true,\n" +
1319                 
"\t\t\"**/*.FBX\":true,\n" +
1320                 
"\t\t\"**/*.lxo\":true,\n" +
1321                 
"\t\t\"**/*.LXO\":true,\n" +
1322                 
"\t\t\"**/*.ma\":true,\n" +
1323                 
"\t\t\"**/*.MA\":true,\n" +
1324                 
"\t\t\"**/*.obj\":true,\n" +
1325                 
"\t\t\"**/*.OBJ\":true,\n" +
1326
1327                 // Unity File Types
1328                 
"\t\t\"**/*.asset\":true,\n" +
1329                 
"\t\t\"**/*.cubemap\":true,\n" +
1330                 
"\t\t\"**/*.flare\":true,\n" +
1331                 
"\t\t\"**/*.mat\":true,\n" +
1332                 
"\t\t\"**/*.meta\":true,\n" +
1333                 
"\t\t\"**/*.prefab\":true,\n" +
1334                 
"\t\t\"**/*.unity\":true,\n" +
1335
1336                 // Folders
1337                 
"\t\t\"build/\":true,\n" +
1338                 
"\t\t\"Build/\":true,\n" +
1339                 
"\t\t\"Library/\":true,\n" +
1340                 
"\t\t\"library/\":true,\n" +
1341                 
"\t\t\"obj/\":true,\n" +
1342                 
"\t\t\"Obj/\":true,\n" +
1343                 
"\t\t\"ProjectSettings/\":true,\r" +
1344                 
"\t\t\"temp/\":true,\n" +
1345                 
"\t\t\"Temp/\":true\n" +
1346                 
"\t}\n" +
1347                 
"}";
1348
1349             // Dont like the replace but it fixes the issue with the JSON
1350             File.WriteAllText(VSCode.SettingsPath, exclusions);
1351         }
1352
1353         
#endregion
1354     }

1355
1356     ///
<summary>
1357     ///
VSCode Asset AssetPostprocessor
1358     ///
<para>This will ensure any time that the project files are generated the VSCode versions will be made</para>
1359     ///
</summary>
1360     ///
<remarks>Undocumented Event</remarks>
1361     
public class VSCodeAssetPostprocessor : AssetPostprocessor
1362     {

1363         ///
<summary>
1364         ///
On documented, project generation event callback
1365         ///
</summary>
1366         
private static void OnGeneratedCSProjectFiles()
1367         {
1368             // Force execution of VSCode update
1369             VSCode.UpdateSolution();
1370         }
1371     }
1372 }


Current Version Number

Current Version Code

Additional File Extensions

Download URL for Unity Debbuger

public const string UnityDebuggerURL = "https:unity.gallery.vsassets.io_apispublicgallerypublisherunityextensionunity-debuglatestassetbynameMicrosoft.VisualStudio.Services.VSIXPackage";

Path to VSCode executable

Value not set, set to "" or current path is invalid, try to autodetect it

If autodetect fails, a error will be printed and the default value set

If its not installed or the install folder isn't a "normal" one,

AutodetectCodePath will print a error message to the Unity Console

Get Program Files Path

The platforms "Program Files" path.

Should debug information be displayed in the Unity terminal?

Is the Visual Studio Code Integration Enabled?

We do not want to automatically turn it on, for in larger projects not everyone is using VSCode

When turning the plugin on, we should remove all the previous project files

Set value

Do not write the launch JSON file because the debugger uses its own

Update launch file

When opening a project in Unity, should it automatically open in VS Code.

Should the launch.json file be written?

Useful to disable if someone has their own custom one rigged up

Should the plugin automatically update itself.

When was the last time that the plugin was updated?

Feature creation date.

Quick reference to the VSCode launch settings file

The full path to the project

Should the script editor be reverted when quiting Unity.

Useful for environments where you do not use VSCode for everything.

Quick reference to the VSCode settings folder

Integration Constructor

Add Update Check

Open VS Code automatically when project is loaded

Event for when script is reloaded

Force Unity To Write Project File

Reflection!

Update the solution files so that they work with VS Code

No need to process if we are not enabled

Try to find automatically the installation of VSCode

return possiblePaths[0]; returns the default one, printing a warning message 'executable not found'

Call VSCode with arguments

Check the path to see if there is "Insiders"

Check for Updates with GitHub

Because were not a runtime framework, lets just use the simplest way of doing this

fileContent = webClient.DownloadString("https:raw.githubusercontent.comdotBunnyVSCodemasterPluginsEditorVSCode.cs");

Don't go any further if there is an error

Set the last update time

Fix for oddity in downlo

Jump over junk characters

Always make sure the file is writable

Write update file

Force update on text file

Checks whether it should auto-open VSCode

VSCode() gets called on Launch and Run, through IntializeOnLoad

https:docs.unity3d.comScriptReferenceInitializeOnLoadAttribute.html

To make sure it only opens VSCode when Unity (re)launches (i.e. opens a project),

we compare the launch time, which we calculate using EditorApplication.timeSinceStartup.

If launch time has changed, then Unity was re-opened

Launch VSCode

Save new launch time

Clear out any existing project files and lingering stuff that might cause problems

Replace with our clean files (only in Unity 5)

Force Unity Preferences Window To Read From Settings

I want that window, please and thank you

Only run this when the editor window is visible (cause its what screwed us up)

Determine what port Unity is listening for on Windows

Not thread safe (yet!)

Manually install the original Unity Debuger

This should auto update to the latest.

Don't go any further if there is an error

Do we have a file to install?

HACK: This is in until Unity can figure out why MD keeps opening even though a different program is selected.

Force the project files to be sync

Load Project

Print a error message to the Unity Console about not finding the code executable

VS Code Integration Preferences Item

Contains all 3 toggles: EnableDisable; Debug OnOff; Writing Launch File OnOff

Need the VS Code executable

TODO: Force Unity To Reload Preferences

This seems to be a hick up issue

Asset Open Callback (from Unity)

Called when Unity is about to open an asset.

bail out if we are not using VSCode

current path without the asset folder

determine asset that has been double clicked in the project view

additional file extensions

open supported object types

call 'open'

Didnt find a code file? let Unity figure it out

Executed when the Editor's playmode changes allowing for capture of required data

Detect when scripts are reloaded and relink playmode detection

Remove extraerroneous lines from a file.

Check Empty

Remove extraerroneous data from project file (content).

Moved to 3.5, 2.0 is legacy.

string targetPath = ""; "Temp" + Path.DirectorySeparatorChar + "bin" + Path.DirectorySeparatorChar + "Debug" + Path.DirectorySeparatorChar + ""; OutputPath

Remove extraerroneous data from solution file (content).

Replace Solution Version

Remove Solution Properties (Unity Junk)

Update Visual Studio Code Launch file

Write out proper formatted JSON (hence no more SimpleJSON here)

Write out proper formatted JSON (hence no more SimpleJSON here)

Update Unity Editor Preferences

Should we turn on this party!

App

Arguments

MonoDevelop Solution

Support Unity Proj (JS)

Restore previous app

Restore previous args

Restore MD setting

Restore MD setting

Always leave editor attaching on, I know, it solves the problem of needing to restart for this

to actually work

Determines if the current path to the code executable is valid or not (exists)

Write Default Workspace Settings

Associations

Hidden Files

Project Files

Media Files

Video

Audio

Textures

Models

Unity File Types

Folders

Dont like the replace but it fixes the issue with the JSON

VSCode Asset AssetPostprocessor

This will ensure any time that the project files are generated the VSCode versions will be made

Undocumented Event

On documented, project generation event callback

Force execution of VSCode update



Gõ tìm kiếm nhanh...